#![cfg_attr(
    all(not(debug_assertions), target_os = "windows"),
    windows_subsystem = "windows"
)]

use tauri::{Manager, WindowEvent, Menu, Submenu, CustomMenuItem};
use std::sync::Arc;
use parking_lot::Mutex;
use anyhow::Result;
use tauri::utils::platform::current_exe;
use std::path::Path;
use memmap2;
use lazy_static::lazy_static;
use std::collections::HashMap;

mod player;
use player::PlaybackManager;

mod config;
use config::{Config, PlayerConfig, PlaybackHistory};

#[derive(Default)]
struct AppState {
    playback_manager: Arc<Mutex<Option<PlaybackManager>>>,
}

impl AppState {
    fn new() -> Self {
        Self {
            playback_manager: Arc::new(Mutex::new(None)),
        }
    }
}

// 确保 AppState 实现了必要的 trait
unsafe impl Send for AppState {}
unsafe impl Sync for AppState {}

// 添加命令结果类型
type CommandResult<T> = Result<T, String>;

lazy_static! {
    static ref FILE_CACHE: parking_lot::Mutex<HashMap<String, Vec<u8>>> = parking_lot::Mutex::new(HashMap::new());
}

// 媒体加载命令
#[tauri::command]
async fn load_media(
    state: tauri::State<'_, AppState>,
    path: String,
) -> CommandResult<()> {
    log::debug!("load_media command received: {}", path);
    
    let mut manager_lock = state.playback_manager.lock();
    let manager = manager_lock.as_mut().ok_or("No playback manager")?;
    
    // 应用配置
    let _ = manager.set_volume(1.0); // 使用默认音量
    
    // 加载媒体
    manager.load_media(&path).map_err(|e| e.to_string())?;
    
    Ok(())
}

// 播放命令
#[tauri::command]
async fn play(state: tauri::State<'_, AppState>) -> CommandResult<()> {
    log::debug!("play command received");
    if let Some(manager) = state.playback_manager.lock().as_ref() {
        manager.play().map_err(|e| e.to_string())?;
    }
    Ok(())
}

// 暂停命令
#[tauri::command]
async fn pause(state: tauri::State<'_, AppState>) -> CommandResult<()> {
    log::debug!("pause command received");
    if let Some(manager) = state.playback_manager.lock().as_ref() {
        manager.pause().map_err(|e| e.to_string())?;
    }
    Ok(())
}

// 跳转命令
#[tauri::command]
async fn seek(
    state: tauri::State<'_, AppState>,
    position: f64,  // 前端传入的是秒
) -> CommandResult<()> {
    log::debug!("seek command received: {} seconds", position);
    if let Some(manager) = state.playback_manager.lock().as_ref() {
        manager.seek(position).map_err(|e| e.to_string())?;
    }
    Ok(())
}

// 音量设置命令
#[tauri::command]
async fn set_volume(
    state: tauri::State<'_, AppState>,
    volume: f32,  // 0.0 到 1.0
) -> CommandResult<()> {
    log::debug!("set_volume command received: {}", volume);
    if let Some(manager) = state.playback_manager.lock().as_ref() {
        manager.set_volume(volume).map_err(|e| e.to_string())?;
    }
    Ok(())
}

// 静音设置命令
#[tauri::command]
async fn set_muted(
    state: tauri::State<'_, AppState>,
    muted: bool,
) -> CommandResult<()> {
    log::debug!("set_muted command received: {}", muted);
    if let Some(manager) = state.playback_manager.lock().as_ref() {
        manager.set_muted(muted).map_err(|e| e.to_string())?;
    }
    Ok(())
}

// 播放速度设置命令
#[tauri::command]
async fn set_speed(
    state: tauri::State<'_, AppState>,
    speed: f32,  // 0.25 到 4.0
) -> CommandResult<()> {
    log::debug!("set_speed command received: {}", speed);
    if let Some(manager) = state.playback_manager.lock().as_ref() {
        manager.set_speed(speed).map_err(|e| e.to_string())?;
    }
    Ok(())
}

// 获取配置命令
#[tauri::command]
async fn get_config(state: tauri::State<'_, AppState>) -> CommandResult<PlayerConfig> {
    let manager = state.playback_manager.lock();
    let config = manager.as_ref().ok_or("No playback manager")?;
    Ok(config.player.clone())
}

// 更新配置命令
#[tauri::command]
async fn update_config(
    state: tauri::State<'_, AppState>,
    config: PlayerConfig,
) -> CommandResult<()> {
    let mut manager = state.playback_manager.lock();
    if let Some(manager) = manager.as_mut() {
        manager.player = config.clone();
        manager.save().map_err(|e| e.to_string())?;
    }
    Ok(())
}

// 获取播放历史命令
#[tauri::command]
async fn get_history(state: tauri::State<'_, AppState>) -> CommandResult<Vec<PlaybackHistory>> {
    let manager = state.playback_manager.lock();
    let config = manager.as_ref().ok_or("No playback manager")?;
    Ok(config.history.clone())
}

// 更新播放位置命令
#[tauri::command]
async fn update_playback_position(
    state: tauri::State<'_, AppState>,
    path: String,
    position: f64,
) -> CommandResult<()> {
    log::debug!("update_playback_position command received: {} at {}", path, position);
    let mut config = state.playback_manager.lock();
    config.as_mut().unwrap().add_to_history(path, position);
    config.as_mut().unwrap().save().map_err(|e| e.to_string())?;
    Ok(())
}

// 获取上次播放位置命令
#[tauri::command]
async fn get_last_position(
    state: tauri::State<'_, AppState>,
    path: String,
) -> CommandResult<Option<f64>> {
    let manager = state.playback_manager.lock();
    let config = manager.as_ref().ok_or("Playback manager not initialized")?;
    Ok(config.get_last_position(&path))
}

#[tauri::command]
async fn init_player(window: tauri::Window, state: tauri::State<'_, AppState>) -> CommandResult<()> {
    log::debug!("Initializing player");
    // 只在 state 中没有 manager 时创建新的
    if state.playback_manager.lock().is_none() {
        let manager = PlaybackManager::new(window.clone());
        *state.playback_manager.lock() = Some(manager);
    }
    Ok(())
}

#[tauri::command]
fn get_file_url(path: String) -> String {
    log::debug!("Converting path to asset URL: {}", path);
    format!("asset://localhost/{}", path.replace("\\", "/"))
}

#[tauri::command]
fn resolve_path(path: String) -> String {
    let abs_path = Path::new(&path)
        .canonicalize()
        .unwrap_or_else(|_| Path::new(&path).to_path_buf());
    
    abs_path.to_string_lossy().replace("\\", "/")
}

fn parse_range(range: Option<&str>, total_size: usize) -> (usize, usize) {
    const CHUNK_SIZE: usize = 1_048_576;
    let default_range = (0, CHUNK_SIZE.min(total_size - 1));
    
    range.and_then(|r| {
        let cleaned = r.replace("bytes=", "");
        let parts = cleaned.split('-').collect::<Vec<_>>();
        match (parts[0].parse(), parts.get(1).and_then(|s| s.parse().ok())) {
            (Ok(start), Some(end)) => Some((start, end)),
            (Ok(start), None) => Some((start, total_size - 1)),
            _ => None
        }
    }).unwrap_or(default_range)
}

fn serve_from_cache(
    cached: &[u8], 
    range: Option<&str>
) -> Result<tauri::http::Response, Box<dyn std::error::Error>> {
    let total_size = cached.len();
    let (start, end) = parse_range(range, total_size);
    
    if cfg!(debug_assertions) {
        log::debug!("Development mode CORS handling");
        return Ok(tauri::http::ResponseBuilder::new()
            .status(206)
            .header("Content-Range", format!("bytes {}-{}/{}", start, end, total_size))
            .header("Accept-Ranges", "bytes")
            .header("Access-Control-Allow-Origin", "http://localhost:1420")
            .header("Access-Control-Allow-Methods", "GET, HEAD")
            .header("Access-Control-Expose-Headers", "Content-Length, Content-Range")
            .header("Vary", "Origin")
            .body(cached[start..=end].to_vec())?);
    }

    tauri::http::ResponseBuilder::new()
        .status(206)
        .header("Content-Range", format!("bytes {}-{}/{}", start, end, total_size))
        .header("Accept-Ranges", "bytes")
        .header("Access-Control-Allow-Origin", "*")
        .header("Access-Control-Allow-Methods", "GET, HEAD")
        .header("Access-Control-Expose-Headers", "Content-Length, Content-Range")
        .header("Vary", "Origin")
        .body(cached[start..=end].to_vec())
}

#[tauri::command]
fn show_about_dialog() {
    // 显示原生关于对话框
    #[cfg(target_os = "macos")]
    {
        use cocoa::appkit::NSApp;
        use cocoa::foundation::NSString;
        use objc::{msg_send, sel, sel_impl};

        unsafe {
            let app = NSApp();
            let title = NSString::alloc(cocoa::base::nil).init_str("AxPlayer");
            let _: () = msg_send![app, orderFrontStandardAboutPanelWithOptions: cocoa::base::nil];
        }
    }
    
    // 其他平台使用tauri的对话框
    #[cfg(not(target_os = "macos"))]
    {
        let _ = tauri::api::dialog::message(
            None::<&tauri::Window>,
            "关于 AxPlayer",
            "AxPlayer\n版本 0.1.0\n基于Tauri和Rust构建"
        );
    }
}

fn main() {
    // 改进日志初始化
    if std::env::var("RUST_LOG").is_err() {
        std::env::set_var("RUST_LOG", "info,axplayer=debug");
    }
    env_logger::builder()
        .format_timestamp_micros()
        .format_target(true)
        .init();
    
    log::info!("AxPlayer starting...");

    let _config = Config::load().unwrap_or_else(|e| {
        log::error!("Failed to load config: {}", e);
        Config::default()
    });

    tauri::Builder::default()
        .menu({
            // 添加应用菜单
            let app_menu = Submenu::new(
                "AxPlayer",  // 在macOS会显示为应用菜单
                Menu::new()
                    .add_item(CustomMenuItem::new("about", "关于 AxPlayer"))
                    .add_native_item(tauri::MenuItem::Separator)
                    .add_item(CustomMenuItem::new("open_file", "打开文件...").accelerator("CmdOrControl+O"))
                    .add_item(CustomMenuItem::new("close_window", "关闭窗口").accelerator("CmdOrControl+W"))
                    .add_native_item(tauri::MenuItem::Separator)
                    .add_native_item(tauri::MenuItem::Quit)
            );
            
            let file_submenu = Submenu::new(
                "文件",
                Menu::new()
                    .add_item(CustomMenuItem::new("open_file", "打开...").accelerator("CmdOrControl+O"))
                    .add_native_item(tauri::MenuItem::Separator)
                    .add_native_item(tauri::MenuItem::Quit)
            );
            
            Menu::new()
                .add_submenu(app_menu)
                .add_submenu(file_submenu)
        })
        .on_menu_event(|event| {
            match event.menu_item_id() {
                "about" => show_about_dialog(),
                "open_file" => event.window().emit("menu-open-file", ()).unwrap(),
                "close_window" => event.window().close().unwrap(),
                "quit" => std::process::exit(0),
                _ => {}
            }
        })
        .register_uri_scheme_protocol("asset", |_app, request| {
            let uri = request.uri();
            log::debug!("Handling asset request: {}", uri);
            
            let path = uri.split('?').next().unwrap_or("");
            let path = path.replace("asset://localhost/", "");
            let resolved_path = std::path::Path::new(&path);
            
            log::info!("Resolving asset path: {}", resolved_path.display());
            
            // 获取文件大小
            let file_size = std::fs::metadata(&path)
                .map(|m| m.len() as usize)
                .unwrap_or(0);
            
            let range_header = request.headers().get("Range").and_then(|v| v.to_str().ok());
            let (start, end) = parse_range(range_header, file_size);

            // 检查缓存
            if let Some(cached) = FILE_CACHE.lock().get(&path) {
                return serve_from_cache(cached, range_header);
            }

            // 处理文件读取
            let file = match std::fs::File::open(&path) {
                Ok(f) => f,
                Err(e) => {
                    log::error!("Failed to open file: {}", e);
                    return Err(e.into());
                }
            };
            
            let mmap = unsafe { memmap2::Mmap::map(&file)? };
            
            // 缓存文件内容
            FILE_CACHE.lock().insert(path.clone(), mmap.to_vec());
            
            // 开发环境特殊处理
            if cfg!(debug_assertions) {
                log::debug!("Development mode CORS handling");
                return Ok(tauri::http::ResponseBuilder::new()
                    .status(206)
                    .header("Content-Range", format!("bytes {}-{}/{}", start, end, file_size))
                    .header("Accept-Ranges", "bytes")
                    .header("Access-Control-Allow-Origin", "http://localhost:1420")
                    .header("Access-Control-Allow-Methods", "GET, HEAD")
                    .header("Access-Control-Expose-Headers", "Content-Length, Content-Range")
                    .header("Vary", "Origin")
                    .body(mmap[start..=end].to_vec())?);
            }

            // 生产环境处理
            let response = tauri::http::ResponseBuilder::new()
                .status(206)
                .header("Content-Range", format!("bytes {}-{}/{}", start, end, file_size))
                .header("Accept-Ranges", "bytes")
                .header("Access-Control-Allow-Origin", "*")
                .header("Access-Control-Allow-Methods", "GET, HEAD")
                .header("Access-Control-Expose-Headers", "Content-Length, Content-Range")
                .header("Vary", "Origin")
                .body(mmap[start..=end].to_vec())?;

            Ok(response)
        })
        .setup(|app| {
            let window = app.get_window("main").unwrap();
            let window_clone = window.clone();
            let app_handle = app.handle();
            
            window.on_window_event(move |event| {
                if let WindowEvent::CloseRequested { api, .. } = event {
                    if let Some(state) = app_handle.try_state::<AppState>() {
                        let mut lock = state.playback_manager.lock();
                        if let Some(manager) = lock.take() {
                            if let Err(e) = manager.cleanup() {
                                log::error!("Error cleaning up manager: {}", e);
                            }
                        }
                    }
                    api.prevent_close();
                    window_clone.close().unwrap();
                }
            });
            
            Ok(())
        })
        .manage(AppState::new())
        .invoke_handler(tauri::generate_handler![
            init_player,
            load_media,
            play,
            pause,
            seek,
            set_volume,
            set_muted,
            set_speed,
            get_config,
            update_config,
            get_history,
            update_playback_position,
            get_last_position,
            get_file_url,
            resolve_path,
        ])
        .run(tauri::generate_context!())
        .expect("error while running tauri application");
}
